﻿using System.Net.Http.Headers;
namespace BPM.Web.Shared.Interceptor;

/// <summary>
/// 提供发送HTTP请求之前或之后引发的事件的数据。
/// </summary>
public class TokenInterceptorEventArgs : EventArgs
{
    /// <summary>
    /// HttpRequestMessage对象使用或用于发送HTTP请求。
    /// </summary>
    public HttpRequestMessage Request { get; }

    /// <summary>
    /// HTTP请求处理程序返回的HttpResponseMessage对象。<br/>
    /// 此属性仅在触发“结束后”事件时可用。
    /// <para>[注意]<br/>不要直接从Response.content属性检索内容。<br/>
    /// 相反，可以调用此事件参数对象的GetCapturedContentAsync()方法来执行此操作。</para>
    /// </summary>
    public HttpResponseMessage Response { get; }

    /// <summary>
    /// 取消发送HTTP请求
    /// </summary>
    public bool Cancel { get; set; }

    private byte[]? _capturedContentBytes;

    private HttpContentHeaders? _capturedContentHeaders;

    internal Task _asyncTask = Task.CompletedTask;

    /// <summary>
    /// 提供发送HTTP请求之前或之后引发的事件的数据。
    /// </summary>
    /// <param name="request">Request</param>
    /// <param name="response">Response</param>
    public TokenInterceptorEventArgs(HttpRequestMessage request, HttpResponseMessage response)
    {
        Request = request;
        Response = response;
        Cancel = false;
    }

    /// <summary>
    /// 获取从HTTP请求返回的HttpContent对象。<br/>
    /// 此方法仅在触发“结束后”事件时可用。<br/>
    /// 可以多次调用此方法。
    /// </summary>
    public async ValueTask<HttpContent> GetCapturedContentAsync()
    {
        if (Response == null)
        {
            throw new InvalidOperationException("只有在触发“AfterEnd”事件时，才能调用GetCapturedContentAsync（）。");
        }

        if (_capturedContentBytes == null)
        {
            _asyncTask = CaptureContentAsync();
            await _asyncTask;
        }

        var httpContent = new ReadOnlyMemoryContent(_capturedContentBytes);
        if (_capturedContentHeaders != null)
        {
            foreach (var contentHeader in _capturedContentHeaders)
            {
                httpContent.Headers.Add(contentHeader.Key, contentHeader.Value);
            }
        }
        return httpContent;
    }

    private async Task CaptureContentAsync()
    {
        await Response.Content.LoadIntoBufferAsync();

        _capturedContentHeaders = Response.Content.Headers;

        _capturedContentBytes = await Response.Content.ReadAsByteArrayAsync();
        var stream = await Response.Content.ReadAsStreamAsync();
        stream.Seek(0, SeekOrigin.Begin);
    }
}
